#include "timer_manager.h"
#include "logger/logger.h"
#include <cassert>

namespace zh
{
    int TimerManager::addTimer(int delayTime, const TimerCallbacks& callback)
    {
        auto timerPtr = std::make_shared<Timer>(delayTime, callback);
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_timerQueue.push(timerPtr);
            m_timerHelperMap.emplace(timerPtr->getID(), timerPtr);
        }
        assert(timerPtr != nullptr);
        return timerPtr->getID();
    }

    bool TimerManager::removeTimer(int id)
    {
        bool removed = false;
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            const auto                  it = m_timerHelperMap.find(id);
            if (it != m_timerHelperMap.end())
            {
                auto timerPtr = it->second.lock();
                if (timerPtr != nullptr)
                {
                    timerPtr->setInvalid();
                }
                m_timerHelperMap.erase(it);
                removed = true;
            }
        }
        return removed;
    }

    bool TimerManager::findTimer(int id)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_timerHelperMap.count(id) > 0;
    }

    std::size_t TimerManager::getTimerCount()
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_timerQueue.size();
    }

    int TimerManager::getNextHandleTime()
    {
        int nextHandleTime = -1;
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            if (!m_timerQueue.empty())
            {
                auto timeUntilExpiration = m_timerQueue.top()->getExpiredTime() - Clock::now();
                nextHandleTime = std::chrono::duration_cast<std::chrono::milliseconds>(timeUntilExpiration).count();
            }
        }
        return nextHandleTime;
    }

    void TimerManager::run()
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        while (!m_timerQueue.empty())
        {
            auto timerPtr = m_timerQueue.top();
            if (timerPtr == nullptr)
            {
                break;
            }
            auto timeUntilExpiration = timerPtr->getExpiredTime() - Clock::now();
            int  waitTime = std::chrono::duration_cast<std::chrono::milliseconds>(timeUntilExpiration).count();
            if (waitTime > 0)
            {
                break;
            }
            if (timerPtr->isValid())
            {
                timerPtr->run();
            }
            m_timerHelperMap.erase(timerPtr->getID());
            m_timerQueue.pop();
        }
    }
} // namespace zh